﻿using MvvmCross.Plugins.Messenger;
using Sidvall.UI.ViewModels;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Sidvall.UI.Views
{
    public class ViewManager : System.IDisposable, IView
    {
        #region Public Members

        #region ViewResources

        private System.Lazy<ViewModelResourceCollection> _ViewResources = new System.Lazy<ViewModelResourceCollection>();
        protected ViewModelResourceCollection ViewResources
        {
            get
            {
                return _ViewResources.Value;
            }
        }

        #endregion

        #region Dispose

        private bool disposed = false;
        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                    UnloadView();
                disposed = true;
            }
        }

        #endregion
        #region OnViewEventAsync

        public Task OnViewEventAsync(ViewEventArgs args)
        {
            if (args == null)
                throw new System.ArgumentNullException("args");
            switch (args.EventType)
            {
                case ViewEventType.ViewUnloaded:
                    UnloadView();
                    break;
                default:
                    break;
            }
            return Task.FromResult(true);
        }

        #endregion
        #region Publish

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public void Publish<TMessage>(TMessage message) where TMessage : MvxMessage
        {
            EventManager.Publish(message);
        }

        #endregion
        #region Subscribe

        public void Subscribe<TMessage>(System.Action<TMessage> deliveryAction) where TMessage : MvxMessage
        {
            this.ViewResources.Add(EventManager.Subscribe(deliveryAction));
        }
        public void Subscribe<TMessage1, TMessage2>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
        {
            this.ViewResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2));
        }
        public void Subscribe<TMessage1, TMessage2, TMessage3>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2,
            System.Action<TMessage3> deliveryAction3)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
            where TMessage3 : MvxMessage
        {
            this.ViewResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2, deliveryAction3));
        }
        public void Subscribe<TMessage1, TMessage2, TMessage3, TMessage4>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2,
            System.Action<TMessage3> deliveryAction3, System.Action<TMessage4> deliveryAction4)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
            where TMessage3 : MvxMessage
            where TMessage4 : MvxMessage
        {
            this.ViewResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2, deliveryAction3, deliveryAction4));
        }

        #endregion
        #region UnloadView

        public void UnloadView()
        {
            var iMax = this.ViewResources.Count;
            for (int i = iMax - 1; i >= 0; i--)
            {
                var viewModelResource = this.ViewResources[i];
                if (viewModelResource != null)
                    viewModelResource.Dispose();
            }
            this.ViewResources.Clear();
        }

        #endregion

        #region GetViewModel

        public static IViewModel GetViewModel(object view)
        {
            if (view == null)
                return null;
            var viewModelProvider = view as IViewModelProvider;
            if ((viewModelProvider != null) && (viewModelProvider.ViewModel != null))
                return viewModelProvider.ViewModel;
            return null;
        }

        #endregion
        #region NotifyViewAsync

        public static async Task<ViewEventArgs> NotifyViewAsync(ViewEventType eventType, IViewModel viewModel)
        {
            var args = new ViewEventArgs(eventType);
            if (viewModel == null)
                return args;
            if (viewModel.ViewModelView == null)
                return args;
            await viewModel.ViewModelView.OnViewEventAsync(args);
            return args;
        }
        public static async Task<ViewEventArgs> NotifyViewAsync(ViewEventType eventType, object view, string regionName)
        {
            var args = new ViewEventArgs(eventType);
            await NotifyViewAsync(args, view, regionName);
            return args;
        }
        public static async Task NotifyViewAsync(ViewEventArgs args, object view, string regionName)
        {
            var item = view as IView;
            if (item != null)
            {
                await item.OnViewEventAsync(args);
            }
            var viewModel = GetViewModel(view);
            if (viewModel != null)
            {
                await viewModel.OnViewEventAsync(args);
            }
        }

        #endregion
        #region NotifyViewsAsync

        public static async Task<ViewEventArgs> NotifyViewsAsync(ViewEventType eventType, IEnumerable<object> views)
        {
            var args = new ViewEventArgs(eventType);
            if (views == null)
                return args;
            foreach (var view in views)
            {
                await NotifyViewAsync(args, view, null);
                if (args.Cancel)
                    return args;
            }
            return args;
        }

        #endregion

        #endregion
        #region Constructors

        public ViewManager()
        {
        }

        #endregion
    }
}
